package com.example.classroom.main;

import cn.hutool.core.lang.Console;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.example.classroom.pojo.*;
import org.jetbrains.annotations.NotNull;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

/**
 * 作者：Rem
 * 时间：2021/12/21 16:08
 */
@Component
public class CreatClassroomPai {


    /**
     * @param courseId 课堂id
     * @param token    老师登录后获得的token
     */
    public void creatExcel(String courseId, String token) throws InterruptedException, ExecutionException {
         /*
            创建目录请求对象
             {"courseid":"MDAwMDAwMDAwMLOGtd2IubexhLVyoQ","contenttype":4,"dirid":0,
            "lessonlink":[],"sort":[],"page":1,"limit":100,"desc":3,"courserole":1,"reqtimestamp":1640085281141}
        */

        // 创建作业id集合
        List<RequestNeed> homeworkIdList = new LinkedList<>();
        // 创建查询对象
        IndexSelect indexSelect = new IndexSelect();
        indexSelect.setCourseid(courseId)
                   .setContenttype(4)
                   .setDirid(0)
                   .setPage(1)
                   .setLimit(200)
                   .setDesc(3)
                   .setCourserole(1);
        // 获得作业目录数据
        IndexJson index = getIndex(indexSelect, token);
        // 获得作业id列表
        List<IndexList> indexLists = index.getData()
                                          .getList();
        for (int i = indexLists.size() - 1; i >= 0; i--) {
            // 倒序添加
            homeworkIdList.add(new RequestNeed(indexLists.get(i)
                                                         .getId(), indexLists.get(i)
                                                                             .getStatistics()
                                                                             .getHomeworkAllCount()));
        }
        // 创建请求集合 方便循环访问每一次作业
        List<List<HomeworkSelect>> homeworkSelectList = new LinkedList<>();
        // 遍历作业id 制作访问请求
        doRequest(homeworkIdList, homeworkSelectList);
        // 制作好后循环访问，获得作业数据添加到分数集合
        // 创建每一次作业对应学生分数的集合
        List<List<User>> homeworkList = getPointList3(token, homeworkSelectList);
        // 创建总map 存放所有学生的数据
        Map<String, List<String>> map = new HashMap<>();
        // 遍历分数集合
        arrangePoint(homeworkList, map);
        // 初始化excel表格
        ArrayList<Map<String, Object>> rows = new ArrayList<>();
        // 将map中的数据整理成表格 遍历
        arrange(indexLists, map, rows);
        // 打印生成excel
        print(indexLists, rows);
    }


    /**
     * 遍历homeworkSelectList里的请求，发出请求
     * 获得数据之后填充到homeworkList
     * getData（）方法是请求接口 如果单线程会非常慢
     *
     * @param token              token
     * @param homeworkSelectList 作业请求集合
     * @return homeworkList       作业分数集合
     */
    private List<List<User>> getPointList3(String token, List<List<HomeworkSelect>> homeworkSelectList)
            throws InterruptedException, ExecutionException {
        // 创建线程池
        ExecutorService executor = Executors.newFixedThreadPool(64);
        // 初始化作业分数集合
        List<List<User>> homeworkList = new LinkedList<>();
        // 初始化Future集合
        List<Future<List<User>>> futureList = new LinkedList<>();
        for (List<HomeworkSelect> select : homeworkSelectList) {
            // 提交一个线程 去查询作业
            Future<List<User>> future = executor.submit(() -> CreatClassroomPai.getData(select, token)
                                                                               .getData()
                                                                               .getList());
            // 将Future加入集合
            futureList.add(future);
        }
        // 线程执行完毕后关闭
        executor.shutdown();
        // 遍历所有Future
        for (Future<List<User>> future : futureList) {
            // 挨个等待线程执行完毕 加入作业分数集合
            homeworkList.add(future.get());
        }
        // 返回作业分数集合
        return homeworkList;
    }

    /**
     * 遍历homeworkSelectList里的请求，发出请求
     * 获得数据之后填充到homeworkList
     * getData（）方法是请求接口 如果单线程会非常慢
     *
     * @param token              token
     * @param homeworkSelectList 作业请求集合
     * @param homeworkList       作业分数集合
     */
    private void getPointList2(String token, @NotNull List<HomeworkSelect> homeworkSelectList, List<List<User>> homeworkList) {
        for (HomeworkSelect select : homeworkSelectList) {
            // 获取学生数据
            ReturnJson data = getData(select, token);
            List<User> userList = data.getData()
                                      .getList();
            homeworkList.add(userList);

        }
    }

    private void arrangePoint(@NotNull List<List<User>> homeworkList, Map<String, List<String>> map) {
        for (List<User> users : homeworkList) {
            for (User user : users) {
                String username = user.getUsername() + "---ID:" + user.getId();
                if (map.containsKey(username)) {
                    // 如果有这个学生，就找到他，往他的分数列表里添加一个分数
                    List<String> gradeList = map.get(username);
                    gradeList.add(user.getGrade());
                } else {
                    // 如果没有这个学生，就往map里面添加
                    List<String> list = new LinkedList<>();
                    list.add(user.getGrade());
                    map.put(username, list);
                }
            }
        }
    }

    /**
     * 制作请求,支持分页
     */
    private void doRequest(List<RequestNeed> classIdList, List<List<HomeworkSelect>> homeworkSelectList) {
        for (RequestNeed requestNeed : classIdList) {
            int count = requestNeed.getCount();
            int index = 1;
            List<HomeworkSelect> list = new LinkedList<>();
            do {
                HomeworkSelect homeworkSelect = new HomeworkSelect();
                homeworkSelect.setHomeworkid(requestNeed.getId())
                              .setPageSize(200)
                              .setCurrentPage(index++);
                list.add(homeworkSelect);
                count -= 200;
            } while (count % 200 > 0);
            homeworkSelectList.add(list);
        }
    }

    private void print(List<IndexList> indexLists, ArrayList<Map<String, Object>> rows) {
        // 通过工具类创建writer
        String path = "d:/classroom" + new Date().getTime() + ".xlsx";
        ExcelWriter writer = ExcelUtil.getWriter(path);
        System.out.println(path);
        // 合并单元格后的标题行，使用默认标题样式
        writer.merge(indexLists.size(), "作业情况");
        // 一次性写出内容，使用默认样式，强制输出标题
        writer.write(rows, true);
        writer.close();
    }

    private void arrange(List<IndexList> indexLists, @NotNull Map<String, List<String>> map, ArrayList<Map<String, Object>> rows) {
        map.forEach((key, value) -> {
            // 因为map的key不能相同，所以成绩之间区分一下
            int count = indexLists.size() - 1;
            // 创建一行
            Map<String, Object> row = new LinkedHashMap<>();
            // 第一列存放username
            row.put("姓名", key.split("---ID:.*")[0]);
            // 遍历value value是学生的成绩列表
            for (String grade : value) {
                if (count < 0) {
                    count = 0;
                }
                //每有一个成绩 添加一列
                row.put(indexLists.get(count)
                                  .getTitle(), grade);
                count--;
            }
            //把这行加入总表
            rows.add(row);

        });
    }

    @NotNull
    public static ReturnJson getData(HomeworkSelect homeworkSelect, String token) {
        String json = JSONObject.toJSONString(homeworkSelect);

        //发起请求
        HttpResponse res = HttpRequest.post("https://openapiv51.ketangpai.com/ReviewApi/getlistByhomework")
                                      .header("token", token)
                                      .body(json)
                                      .execute();
        String returnJson = res.body();
        //获得数据 封装为data
        ReturnJson data = JSON.parseObject(returnJson, ReturnJson.class);
        System.out.println(data.getData()
                               .getList()
                               .size());
        Console.log(data);
        return data;
    }

    @NotNull
    public static ReturnJson getData(List<HomeworkSelect> list, String token) {
        ReturnJson data = new ReturnJson(0, 0, new ReturnData(0, new LinkedList<>()));
        for (HomeworkSelect homeworkSelect : list) {
            String json = JSONObject.toJSONString(homeworkSelect);

            // 发起请求
            HttpResponse res = HttpRequest.post("https://openapiv51.ketangpai.com/ReviewApi/getlistByhomework")
                                          .header("token", token)
                                          .body(json)
                                          .execute();
            String returnJson = res.body();
            // 获得数据 封装为data
            ReturnJson dataPiece = JSON.parseObject(returnJson, ReturnJson.class);
            ReturnData innerData = dataPiece.getData();
            // 获得数量
            int count = innerData.getTotal();
            // 获得集合
            List<User> userListPiece = innerData.getList();
            // 加数量
            data.getData()
                .setTotal(data.getData()
                              .getTotal() + count);
            // 加集合
            data.getData()
                .getList()
                .addAll(userListPiece);
        }
        return data;
    }

    /**
     * {"courseid":"MDAwMDAwMDAwMLOGtd2IubexhLVyoQ","contenttype":4,"dirid":0,"lessonlink":[],"sort":[],"page":1,
     * "limit":100,"desc":3,"courserole":1,"reqtimestamp":1640085281141}
     */
    public IndexJson getIndex(IndexSelect indexSelect, String token) {

        String json = JSONObject.toJSONString(indexSelect);
        // 发起请求
        HttpResponse res = HttpRequest.post("https://openapiv5.ketangpai.com//FutureV2/CourseMeans/getCourseContent")
                                      .header("token", token)
                                      .body(json)
                                      .execute();

        String returnJson = res.body();
        // 获得数据 封装为data
        IndexJson data = JSON.parseObject(returnJson, IndexJson.class);
        Console.log(data);
        return data;
    }
}


